import numpy as np
from . import misc

class MultipleFromBinary:
    '''从二类分类器扩展成多类分类器'''

    def __init__(self, classifier_type):
        self.classifier_type = classifier_type
        self.tree = []
        
    def train(self, xs, cs, params={}):
        self.tree = self._train(xs, np.array(cs))

    def _train(self, xs, cs):
        s = self._split(cs)

        if not s.all():
            _cs = np.ones(len(cs))
            _cs[s] = 0
            classifier = self.classifier_type()
            classifier.train(xs, _cs)
            return [classifier, self._train(xs[s,:], cs[s]), self._train(xs[s==False,:], cs[s==False])]

        else:
            return cs[0]

    def _split(self, cs):
        assert(type(cs) == np.ndarray)
        #return cs == misc.sort_dict(misc.frequency(cs))[-1][0]
        return cs == cs[0]


    def classify(self, xs):
        return [self._classify_single(x, self.tree) for x in xs]

    def _classify_single(self, x, tree):
        if type(tree) == list:
            c = tree[0].classify(np.array([x])) # 0, 1
            return self._classify_single(x, tree[int(c[0])+1])
        else:
            return tree


def _test_multiple_from_binary():
    import logistic_regression as lr


    xs = np.array([[1.0, 1.2], [0.9, 1.1],
                   [8.9, 9.0], [9.0, 9.1],
                   [4.0, 4.0], [5.0, 5.0]])

    cs = ['a', 'a', 'b', 'b', 'c', 'c']

    mb = MultipleFromBinary(lr.LogisticRegression)
    mb.train(xs, cs)
    print(mb.classify(np.array([[2.0, 0.1], [9, 9], [5, 4]])))

def _test_dating():
    import data as mdata
    import logistic_regression as lr
    (xs, cs) = mdata.get_dating_persons()

    mblr = MultipleFromBinary(lr.LogisticRegression)

    mblr.train(np.array(xs, 'float64'), cs)
   
    test_cs = mblr.classify(np.array(xs, 'float64'))
    print(np.array(test_cs) == np.array(cs))

if __name__ == "__main__":
    _test_dating()
